/* 
 * Copyright 2010 Ziya Guven Koylu, Ozge Koylu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.koylu.caffein.model.clazz.validation;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.StringTokenizer;

import org.apache.commons.beanutils.PropertyUtils;

import com.koylu.caffein.validator.Rule;

@SuppressWarnings("serial")
public class ValidationException extends Exception {
	
	/*
		TOKENS:
		--------------
		caffeinConfig --> com.koylu.caffein.model.caffein.CaffeinConfig
		object --> java.lang.Object
		clazz --> com.koylu.caffein.model.clazz.Clazz
		field --> com.koylu.caffein.model.clazz.Field
		fieldName --> java.lang.String
		fieldValue --> java.lang.Object
		validateFor --> java.lang.String
		min --> java.lang.Integer
		max --> java.lang.Integer
		mask --> java.lang.String
		message --> java.lang.String
	 */

	private Rule rule;
	private Map<String, Object> parameterMap;

	public ValidationException(Rule rule, Map<String, Object> parameterMap) {
		super(getErrorMessage(ResourceBundle.getBundle(rule.getResourceBundle(), Locale.getDefault()).getString(rule.getMsg()), parameterMap));
		this.rule = rule;
		this.parameterMap = parameterMap;
	}

	public String getErrorMessage() {
		return getErrorMessage(Locale.getDefault());
	}

	public String getErrorMessage(Locale locale) {
		return getErrorMessage(ResourceBundle.getBundle(rule.getResourceBundle(), locale).getString(rule.getMsg()), parameterMap);
	}

	public Rule getRule() {
		return rule;
	}

	public Map<String, Object> getParameterMap() {
		return parameterMap;
	}

	private static String getErrorMessage(String rowMessage, Map<String, Object> map) {
		List<String> tokens = getTokens(rowMessage);
		for (Iterator<String> iterator = tokens.iterator(); iterator.hasNext();) {
			Object value = null;
			String token = iterator.next();
			if(token.contains(".")){
				try {
					int begin = token.indexOf(".");
					value = PropertyUtils.getNestedProperty(map.get(token.subSequence(0, begin)), token.substring(begin+1, token.length()));					
				} catch (Exception e) {e.printStackTrace();}
			}else{
				value = map.get(token);
			}
			rowMessage = replace(rowMessage, "#{"+token+"}", value == null?"":value.toString());
		}
		return rowMessage;
	}

	private static String replace(String str, String target, String replacement) {
		if (str == null || target == null || replacement == null) {
			return null;
		}
		int k = str.indexOf(target);
		if (k > -1) {
			return str.substring(0, k) + replacement + replace(str.substring(k + target.length(), str.length()), target, replacement);
		}
		return str;
	}
	
	private static List<String> getTokens(String str){
		List<String> list = new ArrayList<String>();
		if(str != null){
			StringTokenizer token = new StringTokenizer(str,"#{");
			while(token.hasMoreTokens()){
				String tokenStr = token.nextToken();
				if(tokenStr.indexOf("}") > -1){
					list.add(tokenStr.substring(0,tokenStr.indexOf("}")));	
				}		
			}
		}
		return list;
	}
}